/*
Implement readv() and writev() using read(), write(), and suitable functions from the
malloc package (Section 7.1.2).
*/

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <strings.h>

struct iovec
{
  void *iov_base;
  size_t iov_len;
};

#define scattered_read_write(operation) \
  ssize_t total_bytes = 0; \
  for (size_t i = 0; i < iovcnt; ++i) \
    { \
      ssize_t bytes_in; \
      if ((bytes_in = operation (fd, iov[i].iov_base, iov[i].iov_len)) \
          == -1) \
        return -1; \
\
      if (bytes_in !=  iov[i].iov_len) \
        return total_bytes + bytes_in; \
\
      total_bytes += bytes_in; \
    } \
\
  return total_bytes;

ssize_t
readv (int fd, const struct iovec *iov, int iovcnt)
{
  scattered_read_write(read)
}

ssize_t
writev (int fd, const struct iovec *iov, int iovcnt)
{
  scattered_read_write(write)
}

int
main (int argc, char *argv[])
{
  if (argc != 2) return EXIT_FAILURE;
  int fd;
  fd = open (argv[1], O_CREAT | O_TRUNC | O_RDWR,
             S_IRWXU | S_IRWXG | S_IRWXO);
  char buffer[13];
  snprintf (buffer, 13, "%s", "Hello,World!");
  struct iovec iov[2] =
    {
     [0] = {
            .iov_base = buffer,
            .iov_len = 6
     },
     [1] = {
            .iov_base = buffer + 6,
            .iov_len = 6
     }
    };
  assert (writev (fd, iov, 2) == 12);
  lseek (fd, 0, SEEK_SET);
  bzero (buffer, 13);
  printf ("buffer empty: %s\n", buffer);
  assert (readv (fd, iov, 2) == 12);
  printf ("buffer reread: %s\n", buffer);
  return EXIT_SUCCESS;
}
